#include "cbb_ph_ymodem_slave.h"
#include "cbb_ph_obj.h"
#include <string.h>


// ymodem slave 功能码
#define YM_SOH 0x01
#define YM_STX 0x02
#define YM_EOT 0x04
#define YM_ACK 0x06
#define YM_NAK 0x15
#define YM_CAN 0x18
#define YM_C   0x43

PH_REG_DEF(cbb_ym_slave, PH_YM_Slave_t)

PH_RET_t 
cbb_ym_slave_monitor(PH_t* pstSelf){
    if(NULL == pstSelf) return PH_ERR;

    // 获取协议对象
    PH_YM_Slave_t* pstYMSlave = GET_PH(pstSelf, PH_YM_Slave_t);

    // 非空闲状态下，tick计数器自增
    if(pstYMSlave->u8Status != YM_STATUS_IDLE) pstYMSlave->u16Tick++;

    // 判断是否超时
    if(pstYMSlave->u16Tick >= pstYMSlave->u16Timeout){

        // 设置空闲状态
        pstYMSlave->u16Tick = 0;
        pstYMSlave->u8Retry = 0;
        pstYMSlave->u8Run = YM_IDLE;
        pstYMSlave->u8Status = YM_STATUS_IDLE;

        // 错误回调函数
        if(NULL != pstYMSlave->pfnErr) pstYMSlave->pfnErr();
    }

    // 正常监控
    return PH_OK;
}

PH_RET_t 
cbb_ym_slave_start(PH_t* pstSelf,PH_Buf_t* pstTxBuffer){

    // 输入参数判断
    if(NULL == pstSelf || NULL == pstTxBuffer || 
        NULL == pstTxBuffer->pu8Buffer || 1 > pstTxBuffer->u32BufferLen) return PH_ERR;

    // 获取协议对象
    PH_YM_Slave_t* pstYMSlave = GET_PH(pstSelf, PH_YM_Slave_t);

    // 防止重复启动 -- 空闲状态才可以开启
    // if(pstYMSlave->u8Status != YM_STATUS_IDLE || pstYMSlave->u8Run != YM_IDLE) return PH_ERR;

    // 等待接收状态
    pstYMSlave->u8Run = YM_RECV;

    // 文件传输开始
    pstYMSlave->u8Status = YM_STATUS_FILE_START;

    // 重置计时次数
    pstYMSlave->u16Tick = 0;

    // 重置重试次数
    pstYMSlave->u8Retry = 0;
        
    // 发送启动标识
    pstTxBuffer->pu8Buffer[0] = YM_C;
    pstTxBuffer->u32DataLen = 1;

    // 启动成功
    return PH_OK;
}

PH_RET_t 
cbb_ym_slave_build(PH_t* pstSelf, PH_Buf_t* pstTxBuffer){
    
    // 判断输入参数有效性
    if(NULL == pstSelf || NULL == pstTxBuffer || 
        NULL == pstTxBuffer->pu8Buffer || 2 > pstTxBuffer->u32BufferLen) return PH_ERR;

    // 获取协议对象
    PH_YM_Slave_t* pstYMSlave = GET_PH(pstSelf, PH_YM_Slave_t);

    // 非发送状态,不进行报文构建
    if(pstYMSlave->u8Run != YM_SEND) return PH_ERR;

    // 等待接收状态
    pstYMSlave->u8Run = YM_RECV;

    // 重置计时
    pstYMSlave->u16Tick = 0;

    // 获取状态
    uint8_t u8Status = pstYMSlave->u8Status;

    // 状态机判断
    switch(u8Status){

        case YM_STATUS_FILE_ACK:
            // 发送ACK和C启动文件数据传输
            pstTxBuffer->pu8Buffer[0] = YM_ACK;
            pstTxBuffer->pu8Buffer[1] = YM_C;
            pstTxBuffer->u32DataLen = 2;
            break;
        case YM_STATUS_FILE_NAK:
            // 发送nak去再次尝试
            pstTxBuffer->pu8Buffer[0] = YM_NAK;
            pstTxBuffer->u32DataLen = 1;
            break;
        case YM_STATUS_DATA_ACK:
            // 发送ACK响应数据传输
            pstTxBuffer->pu8Buffer[0] = YM_ACK;
            pstTxBuffer->u32DataLen = 1;
            break;
        case YM_STATUS_DATA_NAK:
            // 发送NAK尝试再次获取数据
            pstTxBuffer->pu8Buffer[0] = YM_NAK;
            pstTxBuffer->u32DataLen = 1;
            break;
        case YM_STATUS_EOT_NAK:
            // 
            pstTxBuffer->pu8Buffer[0] = YM_NAK;
            pstTxBuffer->u32DataLen = 1;
            break;
        case YM_STATUS_EOT_ACK:
            // send ack to eot
            pstTxBuffer->pu8Buffer[0] = YM_ACK;
            pstTxBuffer->pu8Buffer[1] = YM_C;
            pstTxBuffer->u32DataLen = 2;
            break;
        case YM_STATUS_END_ACK:
            // send ack to end file transfer
            pstTxBuffer->pu8Buffer[0] = YM_ACK;
            pstTxBuffer->u32DataLen = 1;

            // 交互成功
            pstYMSlave->u8Status = YM_STATUS_IDLE;

            // 结束回调函数
            if(NULL != pstYMSlave->pfnEnd) pstYMSlave->pfnEnd();
            break;
        case YM_STATUS_END_NAK:
            // send nak to retry end file transfer
            pstTxBuffer->pu8Buffer[0] = YM_NAK;
            pstTxBuffer->u32DataLen = 1;
            break;
        // 未知状态
        default:return PH_ERR;
    }


    return PH_OK;
}
 
PH_RET_t 
cbb_ym_slave_parse(PH_t* pstSelf,PH_Buf_t* pstRxBuffer){

    // 判断输入参数有效性
    if(NULL == pstSelf || NULL == pstRxBuffer || NULL == pstRxBuffer->pu8Buffer) return PH_ERR;

    // 计算crc
    uint8_t u8Ret = pstSelf->pfnCheck(pstRxBuffer->pu8Buffer, pstRxBuffer->u32DataLen);
    
    // 获取协议对象
    PH_YM_Slave_t* pstYMSlave = GET_PH(pstSelf, PH_YM_Slave_t);

    // 非接收状态,不进行报文构建
    if(pstYMSlave->u8Run != YM_RECV) return PH_ERR;

    // 等待发送状态
    pstYMSlave->u8Run = YM_SEND;

    // 重置计时
    pstYMSlave->u16Tick = 0;

    // 获取状态
    uint8_t u8Status = pstYMSlave->u8Status;

    // 状态机解析
    switch (u8Status){

        // 起始帧
        case YM_STATUS_FILE_START:  
        case YM_STATUS_FILE_NAK:
        {
            if(pstRxBuffer->u32DataLen == 133 && pstRxBuffer->pu8Buffer[0] == YM_SOH &&
                pstRxBuffer->pu8Buffer[1] == 0x00 && pstRxBuffer->pu8Buffer[2] == 0xFF && 
                u8Ret == 1) {
               
                // 重置重试次数
                pstYMSlave->u8Retry = 0;

                // 发送ACK响应文件传输
                pstYMSlave->u8Status = YM_STATUS_FILE_ACK;
            }
            else{

                // 重试超限制
                if(pstYMSlave->u8Retry > YM_MAX_RETRY) goto retry;

                // 重试次数自增
                pstYMSlave->u8Retry++;

                // 发送NAK,再次请求起始帧
                pstYMSlave->u8Status = YM_STATUS_FILE_NAK;
            }
            break;
        }

        // 数据帧
        case YM_STATUS_FILE_ACK:
        case YM_STATUS_DATA_ACK:
        case YM_STATUS_DATA_NAK:
        {

            // 数据接收回调函数
            if(NULL != pstYMSlave->pfnData) pstYMSlave->pfnData(pstRxBuffer->pu8Buffer, pstRxBuffer->u32DataLen);
            
            // EOT结束帧    
            if(1 == pstRxBuffer->u32DataLen && pstRxBuffer->pu8Buffer[0] == YM_EOT){

                // 发送NAK二次确认EOT
                pstYMSlave->u8Status = YM_STATUS_EOT_NAK;
                break;
            }

            // 数据帧
            if( (pstRxBuffer->u32DataLen == 133 || pstRxBuffer->u32DataLen == 1029) && 
                (pstRxBuffer->pu8Buffer[0] == YM_SOH || pstRxBuffer->pu8Buffer[0] == YM_STX) &&
                pstRxBuffer->pu8Buffer[1] == (0xFF - pstRxBuffer->pu8Buffer[2]) && u8Ret == 1) {

                // 重置重试次数
                pstYMSlave->u8Retry = 0;

                // 发送ACK响应数据帧
                pstYMSlave->u8Status = YM_STATUS_DATA_ACK;

                // // 数据接收回调函数
                // if(NULL != pstYMSlave->pfnData) pstYMSlave->pfnData(pstRxBuffer->pu8Buffer, pstRxBuffer->u32DataLen);
            }
            else{

                // 重试超限制
                if(pstYMSlave->u8Retry >= YM_MAX_RETRY) goto retry;

                // 重试次数自增
                pstYMSlave->u8Retry++;

                // 发送NAK,再次请求数据帧
                pstYMSlave->u8Status = YM_STATUS_DATA_NAK;
                
            }
            break;
        }

        // EOT帧
        case YM_STATUS_EOT_NAK:
        {
            if(1 == pstRxBuffer->u32DataLen && pstRxBuffer->pu8Buffer[0] == YM_EOT){

                // 重置重试次数
                pstYMSlave->u8Retry = 0;
                
                // 发送ACK响应EOT
                pstYMSlave->u8Status = YM_STATUS_EOT_ACK;
            }
            else{
                // 重试超限制
                if(pstYMSlave->u8Retry >= YM_MAX_RETRY) goto retry;

                // 重试次数自增
                pstYMSlave->u8Retry++;

                // 发送NAK,再次请求起始帧
                pstYMSlave->u8Status = YM_STATUS_EOT_NAK;
            }
            break;
        }

        // 结束帧
        case YM_STATUS_EOT_ACK:
        case YM_STATUS_END_NAK:
        {
            if(pstRxBuffer->u32DataLen == 133 && pstRxBuffer->pu8Buffer[0] == YM_SOH &&
                pstRxBuffer->pu8Buffer[1] == 0x00 && pstRxBuffer->pu8Buffer[2] == 0xFF && 
                u8Ret == 1) {

                // 重置重试次数
                pstYMSlave->u8Retry = 0;

                // 发送ACK响应结束帧
                pstYMSlave->u8Status = YM_STATUS_END_ACK;
            }
            else{

                // 重试超限制
                if(pstYMSlave->u8Retry >= YM_MAX_RETRY) goto retry;
                
                // 重试次数自增
                pstYMSlave->u8Retry++;

                // 发送NAK,再次请求结束帧
                pstYMSlave->u8Status = YM_STATUS_END_NAK;
            }
            break;
        }

        // 未知状态
        default:return PH_ERR;
    }

    // 传输成功
    return PH_OK;

retry:
    // 设置空闲状态
    pstYMSlave->u16Tick = 0;
    pstYMSlave->u8Retry = 0;
    pstYMSlave->u8Run = YM_IDLE;
    pstYMSlave->u8Status = YM_STATUS_IDLE;

    // 错误回调函数
    if(NULL != pstYMSlave->pfnErr) pstYMSlave->pfnErr();

    // 传输失败
    return PH_ERR;
}
